<?php
/**
 *+------------------
 * Lflow
 *+------------------
 * Copyright (c) 2023~2030 gitee.com/liu_guan_qing All rights reserved.本版权不可删除，侵权必究
 *+------------------
 * Author: Mr.April(405784684@qq.com)
 *+------------------
 */
declare (strict_types=1);

namespace lflow\parser;

use Exception;
use lflow\ckpt\NodeCkpt;
use lflow\ckpt\ProcessCkpt;
use lflow\exceptions\WorkFlowException;
use lflow\lib\util\AssertHelper;
use lflow\lib\util\ObjectHelper;
use lflow\model\ProcessModel;

/**
 * 流程定义json解析并将解析后对象放入模型容器中
 *
 * @author Mr.April
 * @since  1.0
 */
class CpktParser
{

    public static ?ProcessModel $model;

    /**
     * 解析流程定义文件，并将解析后的对象放入模型容器中
     *
     * @param \lflow\model\ProcessModel $model
     *
     * @return \lflow\ckpt\ProcessCkpt
     */
//    public static function parse(ProcessModel $model): ProcessCkpt
//    {
//        self::$modle = $model;
//        $content     = json_decode(json_encode($model->getData('content')));
//        AssertHelper::notNull($content, '流程定义 is null');
//        try {
//            $processCkpt = app()->make(ProcessCkpt::class);
//            $processCkpt->setName($content->{NodeParser::ATTR_NAME} ?? '');
//            $processCkpt->setDisplayName($content->{NodeParser::ATTR_DISPLAYNAME} ?? '');
//            $processCkpt->setExpireTime($content->{NodeParser::ATTR_EXPIRETIME} ?? '');
//            $processCkpt->setInstanceUrl($content->{NodeParser::ATTR_INSTANCEURL} ?? '');
//            $processCkpt->setInstanceNoClass($content->{NodeParser::ATTR_INSTANCENOCLASS} ?? '');
//            $processCkpt->setCallback(ObjectHelper::getObjectValue($content,NodeParser::ATTR_CALLBACK));
//            $nodeList = $content->nodes ?? (object)[];
//            foreach ($nodeList as $rows) {
//                $ckpt    = self::parseModel($rows);
//                $array   = $processCkpt->getNodes();
//                $array[] = $ckpt;
//                $processCkpt->setNodes($array);
//            }
//
//
//            //循环节点模型，构造变迁输入、输出的source、target
//            foreach ($processCkpt->getNodes() as $node) {
//                foreach ($node->getOutputs() as $transition) {
//                    $to = $transition->getTo();
//                    foreach ($processCkpt->getNodes() as $node2) {
//                        if ($to === $node2->getName()) {
//                            $inputs   = $node2->getInputs();
//                            $inputs[] = $transition;
//                            $node2->setInputs($inputs);
//                            $transition->setTarget($node2);
//                        }
//                    }
//                }
//            }
//            return $processCkpt;
//        } catch (\Exception|\Error $e) {
//            throw new WorkFlowException($e->getMessage());
//        }
//    }

    public static function parse(ProcessModel $bytes): ProcessCkpt
    {

        try {
            self::$model = $bytes;
            $processE    = json_decode(json_encode($bytes->getData('content')));
            $process     = new ProcessCkpt();
            $process->setName(ObjectHelper::getObjectValue($processE, NodeParser::ATTR_NAME));
            $process->setDisplayName(ObjectHelper::getObjectValue($processE, NodeParser::ATTR_DISPLAYNAME));
            $process->setExpireTime(ObjectHelper::getObjectValue($processE, NodeParser::ATTR_EXPIRETIME));
            $process->setInstanceUrl(ObjectHelper::getObjectValue($processE, NodeParser::ATTR_INSTANCEURL));
            $process->setInstanceNoClass(ObjectHelper::getObjectValue($processE, NodeParser::ATTR_INSTANCENOCLASS));
            $nodeList = ObjectHelper::getObjectValue($processE, 'nodes');
            foreach ($nodeList as $nodes) {
                $ckpt    = self::parseModel($nodes);
                $array   = $process->getNodes();
                $array[] = $ckpt;
                $process->setNodes($array);
            }

            //循环节点模型，构造变迁输入、输出的source、target
            foreach ($process->getNodes() as $node) {
                foreach ($node->getOutputs() as $transition) {
                    $to = $transition->getTo();
                    foreach ($process->getNodes() as $node2) {
                        if ($to === strtolower($node2->getName())) {
                            $inputs   = $node2->getInputs();
                            $inputs[] = $transition;
                            $node2->setInputs($inputs);
                            $transition->setTarget($node2);
                        }
                    }
                }
            }
            return $process;
        } catch (Exception $e) {
            throw new WorkFlowException($e);
        }
    }

    /**
     * 对流程定义json的节点，根据其节点对应的解析器解析节点内容
     *
     * @param object $node
     *
     * @return \lflow\ckpt\NodeCkpt
     */
    private static function parseModel(object $node): NodeCkpt
    {
        try {
            $parts = explode(":", $node->type);
            $value = $parts[1] ?? '';
            AssertHelper::notNull($value, '解析异常缺少NodeType');
            //\\解决兼容windows&linux 运行
            $parser     = "\\lflow\\parser\\ipml\\" . ucfirst($value) . 'Parser';
            $nodeParser = new $parser();
            $nodeParser->parse(self::$model, $node);
            return $nodeParser->getCkpt();
        } catch (\Exception $e) {
            throw new WorkFlowException($e);
        }
    }
}
